home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / devices / multi-~1.lzh / rawdev.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-25  |  11.4 KB  |  391 lines

  1. /******-----------------------------------------------------******
  2.  * rawdevices - a multi-devices driver for raw floppy disks      *
  3.  * for PURE_C 1.1                                                *
  4.  *                                                               *
  5.  * This is Dave Gymer's raw MiNT floppy device hacked up         *
  6.  * by Stephane Boisson (boisso_s@epita.fr)                       *
  7.  * and is hereby placed in the public domain.                    *
  8.  *                                                               *
  9.  ******-----------------------------------------------------******/
  10.  
  11. #include <tos.h>                        /* for Floprd & Flopwr */
  12. #include <string.h>
  13. #include <mint\filesys.h>
  14. #include <mint\kernel.h>
  15. #include <mint\atarierr.h>
  16.  
  17. #pragma warn -par
  18. #pragma warn -pro
  19.  
  20. #define DEBUG__(x) DEBUG(x)
  21. #define TRACE__(x) /* TRACE(x) */
  22. #define ALERT__(x) ALERT(x)
  23. #define FATAL__(x) FATAL(x)
  24.  
  25. static long cdecl floppy_open(FILEPTR *f);
  26. static long cdecl floppy_write(FILEPTR *f, char *buf, long bytes);
  27. static long cdecl floppy_read(FILEPTR *f, char *buf, long bytes);
  28. static long cdecl floppy_lseek(FILEPTR *f, long where, int whence);
  29. static long cdecl floppy_ioctl(FILEPTR *f, int mode, void *buf);
  30. static long cdecl floppy_datime(FILEPTR *f, short *timeptr, int wrflag);
  31. static long cdecl floppy_close(FILEPTR *f, int pid);
  32. static long cdecl floppy_select(FILEPTR *f, long proc, int mode);
  33. static void cdecl floppy_unselect(FILEPTR *f, long proc, int mode);
  34.  
  35. static DEVDRV floppy_device = {
  36.     floppy_open, floppy_write, floppy_read, floppy_lseek, floppy_ioctl,
  37.     floppy_datime, floppy_close, floppy_select, floppy_unselect,
  38.     0, 0, 0
  39. };
  40.  
  41. typedef struct {
  42.     char *name;                /* Device name */
  43.     int drive;                /* BIOS drive number, 0 == A:, 1 == B: */
  44.     int tracks;                /* tracks per disk */
  45.     int sides;                /* sides per track */
  46.     int sectors;            /* sectors per track */
  47.     int secsize;            /* bytes per sector */
  48.     long blocksize;        /* calculated... */
  49. } RAWDEV;
  50.  
  51. /* characteristics of the floppies*/
  52. static RAWDEV drivers[]= {
  53.     {"fd0", 0, 80, 2, 9, 512},            /* 720 kbyte Double density */
  54.     {"fh0", 0, 80, 2, 18, 512},            /* 1.44 meg high density */
  55.     {"fx0", 0, 80, 2, 20, 512}            /* 1.6 meg fat high density */
  56. };
  57.     
  58.  
  59. /* kernel information */
  60. struct kerinfo *kernel;
  61.  
  62. /* Install time, for floppy_datime. */
  63. static int install_date;
  64. static int install_time;
  65.  
  66. /* structure to hold a block buffer */
  67. typedef struct floppy_block {
  68.     short dev_id;
  69.     int track;
  70.     int side;
  71.     long byte;
  72.     enum {
  73.         INVALID, VALID, DIRTY, ATEOF
  74.     } state;
  75.     char *buffer;
  76. } FLOBLOCK;
  77.  
  78. static char name[32]="u:\\dev\\";
  79.  
  80. struct dev_descr devinfo = {
  81.     &floppy_device, 0, 0, (struct tty *)0, 0L, 0L, 0L, 0L
  82. };
  83.  
  84.  
  85. /**
  86.  * Initial setup, return the device driver to the OS
  87. **/
  88. DEVDRV * cdecl floppy_init(struct kerinfo *k)
  89. {
  90.     long result;
  91.     int i, len;
  92.     
  93.     kernel= k;
  94.     TRACE__(("[RAWDEV] floppy_init: init raw devices"));
  95.     len= strlen(name);
  96.     CCONWS("Raw floppy devices for MiNT (" __DATE__ ")\r\n");
  97.     for(i=0; i<(sizeof(drivers) / sizeof(RAWDEV)); i++)
  98.     {
  99.         strcpy(name+len, drivers[i].name);
  100.         devinfo.dinfo= i;
  101.         drivers[i].blocksize= ((long) drivers[i].secsize) * drivers[i].sectors; 
  102.         TRACE__(("[RAWDEV] floppy_init: device [%s]", name));
  103.         if(DCNTL(DEV_INSTALL, name, (long)&devinfo)<=0)
  104.             ALERT__(("[RAWDEV] floppy_init: Unable to install %s", name));
  105.     }
  106.     install_time= TGETTIME();
  107.     install_date= TGETDATE();
  108.  
  109.     return((DEVDRV *) 1L);
  110. }
  111.  
  112. /*****
  113.  * utility functions
  114.  * note that blocks are whole tracks
  115.  *****/
  116.  
  117. /*>>>>>>>>>>>>>>>>>>>>>> read a block <<<<<<<<<<<<<<<<<<<<<<<<*/
  118. static int read_block(FLOBLOCK *floblock)
  119. {
  120.     int rv;
  121.  
  122.     TRACE__(("[RAWDEV] read_block: drive #%d, track #%d, side %d", 
  123.         drivers[floblock->dev_id].drive, floblock->track, floblock->side));
  124.  
  125.     rv = Floprd(floblock->buffer, 0L, drivers[floblock->dev_id].drive,
  126.         1, floblock->track, floblock->side,
  127.         drivers[floblock->dev_id].sectors);
  128.         
  129.     if (rv)
  130.     {
  131.         DEBUG__(("[RAWDEV] read_block: Floprd error #%d", rv));
  132.         floblock->state = INVALID;
  133.     }
  134.     else
  135.         floblock->state = VALID;
  136.     return(rv);
  137. }
  138.  
  139. /*>>>>>>>>>>>>>>>>>>>> flush a block <<<<<<<<<<<<<<<<<<<<<<<<<<*/
  140. static int flush_block(FLOBLOCK *floblock)
  141. {
  142.     int rv;
  143.  
  144.     if (floblock->state != DIRTY)
  145.         return 0;
  146.  
  147.     TRACE__(("[RAWDEV] flush_block: drive #%d, track #%d, side %d", 
  148.         drivers[floblock->dev_id].drive, floblock->track, floblock->side));
  149.  
  150.     rv = Flopwr(floblock->buffer, 0L, drivers[floblock->dev_id].drive,
  151.         1, floblock->track, floblock->side,
  152.         drivers[floblock->dev_id].sectors);
  153.  
  154.     if (rv)
  155.         DEBUG__(("[RAWDEV] flush_block: Flopwr error #%d", rv));
  156.     else
  157.         floblock->state = VALID;
  158.     return(rv);
  159. }
  160.  
  161. /*>>>>>>>> convert long seek position into floppy_block <<<<<<<<*/
  162. static void seek2int(long pos, FLOBLOCK *floblock)
  163. {
  164.     TRACE__(("[RAWDEV] seek2int: convert long seek position #%ld", pos));
  165.     if (pos < 0) pos = 0;
  166.     floblock->byte = pos % drivers[floblock->dev_id].blocksize;
  167.     pos /= drivers[floblock->dev_id].blocksize;
  168.     floblock->side = (int)(pos % drivers[floblock->dev_id].sides);
  169.     pos /= drivers[floblock->dev_id].sides;
  170.     floblock->track = (int)pos;
  171.  
  172.     if (floblock->track >= drivers[floblock->dev_id].tracks)
  173.     {
  174.         floblock->track = drivers[floblock->dev_id].tracks;
  175.         floblock->side = 0;
  176.         floblock->byte = 0;
  177.         floblock->state = ATEOF;
  178.     }
  179. }
  180.  
  181. /*>>>>>>>> convert floppy_block into long seek position <<<<<<<*/
  182. static long int2seek(FLOBLOCK *floblock)
  183. {
  184.     TRACE__(("[RAWDEV] int2seek: convert floppy_block"));
  185.     return ((long)floblock->track * drivers[floblock->dev_id].sides
  186.         + floblock->side) * drivers[floblock->dev_id].blocksize + floblock->byte;
  187. }
  188.  
  189. /*>>>> move to next block - read it, after flushing the old one <<<<<*/
  190. static int next_block(FLOBLOCK *floblock)
  191. {
  192.     int rv = 0;
  193.  
  194.     TRACE__(("[RAWDEV] next_block: move to next block"));
  195.     if (floblock->state != ATEOF)
  196.     {
  197.         rv = flush_block(floblock);
  198.         if (++floblock->side == drivers[floblock->dev_id].sides)
  199.         {
  200.             floblock->side = 0;
  201.             if (++floblock->track == drivers[floblock->dev_id].tracks)
  202.             {
  203.                 DEBUG__(("[RAWDEV] next_block: end of file"));
  204.                 floblock->state = ATEOF;
  205.                 floblock->side = 0;
  206.             }
  207.         }
  208.         if (floblock->state != ATEOF)
  209.             if (rv)
  210.                 floblock->state = INVALID;
  211.             else
  212.                 rv = read_block(floblock);
  213.         floblock->byte = 0;
  214.     }
  215.     return(rv);
  216. }
  217.  
  218. /*****
  219.  * here are the actual device driver functions
  220.  *****/
  221. static long cdecl floppy_open(FILEPTR *f)
  222. {
  223.     FLOBLOCK *floblock;
  224.  
  225.     TRACE__(("[RAWDEV] floppy_open: open device %s", drivers[f->fc.aux].name));
  226.     floblock = (FLOBLOCK *)kmalloc(sizeof(FLOBLOCK));
  227.     if (!floblock)
  228.     {
  229.         ALERT__(("[RAWDEV] floppy_open: out of memory for FLOBLOCK"));
  230.         return (ENSMEM);
  231.     }
  232.  
  233.     floblock->buffer = (char *)kmalloc(drivers[f->fc.aux].blocksize);
  234.     if (!floblock->buffer)
  235.     {
  236.         ALERT__(("[RAWDEV] floppy_open: out of memory for blocksize"));
  237.         return (ENSMEM);
  238.     }
  239.  
  240.     f->devinfo = (long)floblock;
  241.     floblock->state = INVALID;
  242.     floblock->track = 0;
  243.     floblock->side = 0;
  244.     floblock->byte = 0;
  245.     floblock->dev_id= f->fc.aux;
  246.     return (0);
  247. }
  248.  
  249. static long cdecl floppy_write(FILEPTR *f, char *buf, long bytes)
  250. {
  251.     FLOBLOCK *floblock = (FLOBLOCK *)f->devinfo;
  252.     int rv = 0;
  253.     long bytes_written = 0;
  254.     
  255.     TRACE__(("[RAWDEV] floppy_write: write %ld bytes to %s", bytes, drivers[f->fc.aux].name));
  256.  
  257.     if (floblock->state == INVALID) rv= read_block(floblock);     /* not started yet */
  258.  
  259.     /* keep going until we've written enough, or there's an error or EOF */
  260.     while (!rv && floblock->state != ATEOF && bytes)
  261.     {
  262.         if (floblock->byte < drivers[floblock->dev_id].blocksize) /* data in buffer */
  263.         {
  264.             char *ptr = floblock->buffer + floblock->byte;
  265.             long num = drivers[floblock->dev_id].blocksize - floblock->byte;
  266.  
  267.             if (num > bytes) num = bytes;
  268.             bytes_written += num;
  269.             bytes -= num;
  270.             floblock->byte += num;
  271.             while (num--)    *ptr++ = *buf++;
  272. /*        memcpy(ptr, buf, num); */
  273.             floblock->state = DIRTY;
  274.         }
  275.         else                    /* must get next block */
  276.             rv = next_block(floblock);
  277.     }
  278.     return rv ? rv : bytes_written;
  279. }
  280.  
  281. static long cdecl floppy_read(FILEPTR *f, char *buf, long bytes)
  282. {
  283.     FLOBLOCK *floblock = (FLOBLOCK *)f->devinfo;
  284.     int rv = 0;
  285.     long bytes_read = 0;
  286.     
  287.     TRACE__(("[RAWDEV] floppy_read: read %ld bytes from %s", bytes, drivers[f->fc.aux].name));
  288.     if (floblock->state == INVALID) rv = read_block(floblock);        /* not started yet */
  289.  
  290.     /* keep going until we've read enough, or there's an error or EOF */
  291.     while (!rv && floblock->state != ATEOF && bytes)
  292.     {
  293.         if (floblock->byte < drivers[floblock->dev_id].blocksize)        /* data in buffer */
  294.         {
  295.             char *ptr = floblock->buffer + floblock->byte;
  296.             long num = drivers[floblock->dev_id].blocksize - floblock->byte;
  297.  
  298.             if (num > bytes) num = bytes;
  299.             bytes_read += num;
  300.             bytes -= num;
  301.             floblock->byte += num;
  302.             while (num--) *buf++ = *ptr++;
  303. /*            memcpy(buf, ptr, num); */
  304.         }
  305.         else                    /* must get next block */
  306.             rv = next_block(floblock);
  307.     }
  308.     return rv ? rv : bytes_read;
  309. }
  310.  
  311. static long cdecl floppy_lseek(FILEPTR *f, long where, int whence)
  312. {
  313.     long newpos = where;
  314.     FLOBLOCK *floblock = (FLOBLOCK *)f->devinfo;
  315.  
  316.     TRACE__(("[RAWDEV] floppy_lseek: seek mode %d of %ld on %s", whence, where, drivers[f->fc.aux].name));
  317.     switch (whence)
  318.     {
  319.         case SEEK_SET:
  320.             break;
  321.         case SEEK_CUR:
  322.             newpos += int2seek(floblock);
  323.             break;
  324.         case SEEK_END:
  325.             newpos = drivers[floblock->dev_id].sides
  326.                 * drivers[floblock->dev_id].tracks * drivers[floblock->dev_id].blocksize - newpos;
  327.             break;
  328.         default:
  329.             DEBUG__(("[RAWDEV] floppy_lseek: illegal whence (%d) in seek for %s", whence, drivers[floblock->dev_id].name));
  330.             return ERANGE;
  331.     }
  332.     if (int2seek(floblock) % drivers[floblock->dev_id].blocksize != newpos % drivers[floblock->dev_id].blocksize)
  333.     {
  334.         if (flush_block(floblock))
  335.             DEBUG__(("[RAWDEV] floppy_lseek: flush_block failed on %s",drivers[floblock->dev_id].name));
  336.         floblock->state = INVALID;
  337.     }
  338.     seek2int(newpos, floblock);
  339.     return newpos;
  340. }
  341.  
  342. static long cdecl floppy_ioctl(FILEPTR *f, int mode, void *buf)
  343. {
  344.     TRACE__(("[RAWDEV] floppy_ioctl: mode %d on %s", mode, drivers[f->fc.aux].name));
  345.     switch (mode) {
  346.         case FIONREAD:
  347.         case FIONWRITE:
  348.             /*
  349.              * we never block - use BLOCKSIZE as a sensible
  350.              * number to read as a chunk
  351.              */
  352.             *((long *)buf) = drivers[f->fc.aux].secsize * drivers[f->fc.aux].sectors ;
  353.             TRACE__(("[RAWDEV] floppy_ioctl: FIONREAD/FIONWRITE on %s -> %ld", drivers[f->fc.aux].name, *((long *)buf)));
  354.             return (0);
  355.         default:
  356.             return EINTRN;
  357.     }
  358. }
  359.  
  360. static long cdecl floppy_datime(FILEPTR *f, short *timeptr, int wrflag)
  361. {
  362.     TRACE__(("[RAWDEV] floppy_datime: on %s", drivers[f->fc.aux].name));
  363.     if (wrflag) return EINVFN;
  364.     *timeptr++ = install_time;
  365.     *timeptr = install_date;
  366.     return (0);
  367. }
  368.  
  369. static long cdecl floppy_close(FILEPTR *f, int pid)
  370. {
  371.     int rv = 0;
  372.     FLOBLOCK *floblock = (FLOBLOCK *)f->devinfo;
  373.  
  374.     TRACE__(("[RAWDEV] floppy_close: %s by pid #%d", drivers[f->fc.aux].name, pid));
  375.     if (!f->links) {
  376.         rv = flush_block(floblock);    /* flush the buffer */
  377.         kfree(floblock->buffer);
  378.         kfree(floblock);
  379.     }
  380.     return rv;
  381. }
  382.  
  383. static long cdecl floppy_select(FILEPTR *f, long proc, int mode)
  384. {
  385.     TRACE__(("[RAWDEV] floppy_select: %s always ready!", drivers[f->fc.aux].name));
  386.     return 1;                    /* we're always ready for I/O */
  387. }
  388.  
  389. static void cdecl floppy_unselect(FILEPTR *f, long proc, int mode)
  390. {
  391.     TRACE__(("[RAWDEV] floppy_unselect: %s (nothing to do)", drivers[f->fc.aux].name));
  392.     /* nothing for us to do here */
  393. }
  394.